package com.sdy.mvc.feign;

import com.sdy.mvc.utils.JsonUtil;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;

import static feign.FeignException.errorStatus;

/**
 * @author zhouziqiang
 */
@Slf4j
public class FeignSpringErrorDecoder implements ErrorDecoder {
    @Override
    public Exception decode(String methodKey, Response response) {
        if (response.status() == 799) {
            com.sdy.common.model.Response result;
            try (InputStream is = response.body().asInputStream();
                 ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int n;
                while (-1 != (n = is.read(buffer))) {
                    output.write(buffer, 0, n);
                }
                byte[] data = output.toByteArray();
                output.close();
                try {
                    result = JsonUtil.deserialize(Base64.getDecoder().decode(data), com.sdy.common.model.Response.class);
                } catch (Exception e) {
                    log.error("FeignSpringErrorDecoder deserialize error![{}]", e.getMessage());
                    throw e;
                }
            } catch (IOException e) {
                log.error("", e);
                throw new RuntimeException("FeignSpringErrorDecoder response stream io error! " + e.getMessage());
            }
            try {
                String exceptionPackage = (String) result.getData();
                Constructor ct = Class.forName(exceptionPackage).getDeclaredConstructor(String.class);
                ct.setAccessible(true);
                return (Exception) ct.newInstance(result.getMessage());
            } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException
                    | InvocationTargetException e) {
                throw new RuntimeException(result.getMessage());
            }
        }
        return errorStatus(methodKey, response);
    }
}